package org.wevil.util;

import org.wevil.dto.FlowNodeSeq;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.Process;
import org.camunda.bpm.model.bpmn.instance.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;

/**
 * xml工具类
 *
 * @author wanglei
 * @since 2024-02-29
 */
public class XmlUtil {

    // camunda 解析 bpmn xml 文件内容
    public static List<FlowNodeSeq> camunda() throws IOException {
        InputStream is = Files.newInputStream(new File("D:\\付款申请V2.bpmn").toPath());
        BpmnModelInstance modelInstance = Bpmn.readModelFromStream(is);
        Collection<Process> processes = modelInstance.getDefinitions().getChildElementsByType(Process.class);

        List<FlowNodeSeq> seqList = new ArrayList<>();
        for (Process process : processes) {
            Collection<FlowElement> flowElements = process.getFlowElements();
            for (FlowElement element : flowElements) {
                if (element instanceof StartEvent) {
                    List<String> outIdList = ((StartEvent) element).getOutgoing().stream().map(SequenceFlow::getId).collect(Collectors.toList());
//                    String format = String.format("开始[id=%s, name=%s, outIdList=%s]", element.getId(), element.getName(), outIdList);
//                    System.out.println(format);
                    FlowNodeSeq seq = new FlowNodeSeq(1, element.getId(), element.getName(), "开始", outIdList);
                    seqList.add(seq);
                }
                else if (element instanceof Task) {
                    List<String> inIdList = ((Task) element).getIncoming().stream().map(SequenceFlow::getId).collect(Collectors.toList());
                    List<String> outIdList = ((Task) element).getOutgoing().stream().map(SequenceFlow::getId).collect(Collectors.toList());
                    String format = String.format("任务[id=%s, name=%s, inIdList=%s, outIdList=%s]",
                            element.getId(),
                            element.getName(),
                            inIdList,
                            outIdList
                    );
//                    System.out.println(format);
                    FlowNodeSeq seq = new FlowNodeSeq(0, element.getId(), element.getName(), "任务", outIdList);
                    seqList.add(seq);
                }
                else if (element instanceof Gateway) {
                    List<String> inIdList = ((Gateway) element).getIncoming().stream().map(SequenceFlow::getId).collect(Collectors.toList());
                    List<String> outIdList = ((Gateway) element).getOutgoing().stream().map(SequenceFlow::getId).collect(Collectors.toList());
                    String format = String.format("网关[id=%s, name=%s, inIdList=%s, outIdList=%s]",
                            element.getId(),
                            element.getName(),
                            inIdList,
                            outIdList
                    );
//                    System.out.println(format);
                    FlowNodeSeq seq = new FlowNodeSeq(0, element.getId(), element.getName(), "网关", outIdList);
                    seqList.add(seq);
                }
                else if (element instanceof EndEvent){
                    List<String> inIdList = ((EndEvent) element).getIncoming().stream().map(SequenceFlow::getId).collect(Collectors.toList());
                    String format = String.format("结束[id=%s, name=%s, inIdList=%s]", element.getId(), element.getName(), inIdList);
                    //System.out.println(format);
                    FlowNodeSeq seq = new FlowNodeSeq(0, element.getId(), element.getName(), "结束", null);
                    seqList.add(seq);
                }
                else if (element instanceof SequenceFlow){
                    String format = String.format("流程转向[id=%s, name=%s, inIdList=%s, outIdList=%s]",
                            element.getId(),
                            element.getName(),
                            ((SequenceFlow) element).getSource().getId(),
                            ((SequenceFlow) element).getTarget().getId());
                    //System.out.println(format);
                    FlowNodeSeq seq = new FlowNodeSeq(0, element.getId(), element.getName(), "流程转向", Collections.singletonList(((SequenceFlow) element).getTarget().getId()));
                    seqList.add(seq);
                }
            }
        }
        sortFlow(seqList);
        seqList = seqList.stream().sorted(Comparator.comparing(FlowNodeSeq::getIndex)).collect(Collectors.toList());
        return seqList;
    }

    // 流程排序
    private static void sortFlow(List<FlowNodeSeq> flowList){
        List<FlowNodeSeq> sortedList = new ArrayList<>();
        // 获取开始节点
        FlowNodeSeq startFlow = flowList.stream().filter(f -> f.getIndex()==1).collect(Collectors.toList()).get(0);
        sortedList.add(startFlow);
        // 获取当前节点的下一个节点，设置下一个节点index+1
        setFlowIndex(startFlow, flowList);
    }

    // 设置当前节点的下一个节点的index+1
    private static void setFlowIndex(FlowNodeSeq currentNode, List<FlowNodeSeq> flowList){
        List<String> nextIdList = currentNode.getNextId();
        if(nextIdList!=null){
            for(FlowNodeSeq flow : flowList){
                if(nextIdList.contains(flow.getId())){
                    // 如果碰到了循环，结束递归
                    if(flow.getIndex()!=null && flow.getIndex()>1){
                        continue;
                    }
                    flow.setIndex(currentNode.getIndex()+1);
                    setFlowIndex(flow, flowList);
                }
            }
        }
    }
}
